package com.github.soiff.shadow.plugins;

import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Helper;
import com.github.soiff.shadow.api.Plugin;
import com.github.soiff.shadow.definition.Global;
import com.github.soiff.shadow.definition.Handler;
import com.github.soiff.shadow.error.Errors;
import com.github.soiff.shadow.loader.ResourceLoader;
import com.github.soiff.shadow.common.ResourceFinder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by Soiff on 2016/05/20.
 *
 * @author : Soiff
 */
@Component
public class Controller {

    @Autowired
    Handlebars handlebars;

    final private Global global = new Global(new StandardEnvironment());

    private final ConcurrentHashMap<String, Context> contexts = new ConcurrentHashMap<>(1);

    public Map<String, Errors> registerPlugin (final String alias, final String file, final String classpath) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        final ClassLoader loader = new ResourceLoader(new File(file), new File(classpath));
        final ResourceFinder finder = new ResourceFinder("META-INF/services/", loader);

        final List<String> resources = new ArrayList<>(1);
        final List<Plugin> plugins = new ArrayList<>(1);
        /* ResourceFinder("", loader) will be used for loading template. */
        final Context context = new Context(loader, new ResourceFinder("", loader), plugins, resources);

        List<Class> classes = finder.findAllImplementations(Plugin.class);
        final Iterator<Class> iterator = classes.iterator();
        Class clazz;
        Plugin plugin;
        final Map<String, Errors> result = new HashMap<>(1);
        boolean initialized;
        while (iterator.hasNext()) {
            clazz = iterator.next();
            plugin = (Plugin) clazz.newInstance();
            //TODO: add proper Global (context).
            initialized = plugin.initial(global);
            if (initialized) {
                resources.add(plugin.resources());
                plugins.add(plugin);
                for (Handler<Helper> handler : plugin.handlers())
                    handlebars.registerHelper(handler.getDirective(), handler.getHandler());
            }
            result.put(alias, Errors.valueOf(initialized));
        }

        contexts.put(alias, context);

        return result;
    }
}
